package com.lollipop.synthential.algorithm;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: J.K
 * @Date: 2022-07-29 13:46
 * @Description: 轮询算法
 *
 * 轮询算法的优势：
 *
 * 算法实现简单，请求分发效率够高。
 * 能够将所有请求均摊到集群中的每个节点上。
 * 易于后期弹性伸缩，业务增长时可以拓展节点，业务萎靡时可以缩减节点。
 *
 * 轮询算法的劣势：
 *
 * 对于不同配置的服务器无法合理照顾，无法将高配置的服务器性能发挥出来。
 * 由于请求分发时，是基于请求序列号来实现的，所以无法保证同一客户端的请求都是由同一节点处理的，因此需要通过 session 记录状态时，无法确保其一致性。

 * 轮询算法的应用场景：
 *
 * 集群中所有节点硬件配置都相同的情况。
 * 只读不写，无需保持状态的情景。
 */
@Slf4j
public class RoundRibbon {
    /**
     * 记录当前请求序列号
     */
    private static AtomicInteger requestIndex = new AtomicInteger(0);

    /**
     * 获取服务节点
     *
     * @return
     */
    public static String getServer() {
        // 用请求序列号取余集群节点数量，求得本次处理请求的节点下标
        int index = requestIndex.get() % Servers.SERVERS.size();

        // 从服务器列表中获取具体的节点IP地址信息
        String server = Servers.SERVERS.get(index);

        // 自增一次请求序列号，方便下个请求计算
        requestIndex.incrementAndGet();

        // 返回获取到的服务器IP地址
        return server;
    }

    public static void main(String[] args) {
        // 模拟10个请求
        for (int i = 0; i < 10; i++) {
            log.info("第[{}]个请求，服务节点：[{}]", i, RoundRibbon.getServer());
        }
    }
}
